package com.xy.iot.common.utils;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.json.JSONUtil;
import com.xy.iot.common.enums.MessageFormatDataEnum;
import com.xy.iot.common.result.message.JSONMessageData;
import lombok.extern.slf4j.Slf4j;
import org.mozilla.universalchardet.UniversalDetector;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author: niuniu
 * @Date: 2024/6/10 16:53
 * @Description:
 */
@Slf4j
public class CommonUtil {
    private static final Pattern HEX_PATTERN = Pattern.compile("^[0-9A-Fa-f]{2}( [0-9A-Fa-f]{2})*$");
    public final static String HEX_ENCODING = "hex";
    /**
     *  判断是否是基本数据类型
     * @param cls
     * @return
     */
    public static boolean isWrapperType(Class<?> cls) {
        //基本数据类型
        List<Class<?>> wrapperTypes = new ArrayList<>();
        wrapperTypes.add(Boolean.class);
        wrapperTypes.add(Byte.class);
        wrapperTypes.add(Character.class);
        wrapperTypes.add(Short.class);
        wrapperTypes.add(Integer.class);
        wrapperTypes.add(Long.class);
        wrapperTypes.add(Float.class);
        wrapperTypes.add(Double.class);
        wrapperTypes.add(String.class);
        for (Class<?> wrapper : wrapperTypes) {
            if (wrapper.isAssignableFrom(cls)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 将字符串，编码转换为十六进制表示
     * @param s
     * @return
     */
    public static String encodeHexStr(String s) {
        return HexUtil.encodeHexStr(s.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 将十六进制字符数组转换为字符串，默认编码UTF-8
     * @param s
     * @return
     */
    public static String decodeHexStr(String s) {
        return HexUtil.decodeHexStr(s);
    }

    /**
     * byte数组16进制数据，转成字符串
     * @param bytes
     * @return
     */
    public static String byteToDecodeHexStr(byte[] bytes) {
        return decodeHexStr(HexUtil.encodeHexStr(bytes));
    }
    /**
     * 使用正则表达式判断字符串是否符合无前导符号的16进制数据格式。
     * @param hexData 待检查的字符串，预期格式为 "XX XX XX..."，其中XX为16进制数。
     * @return 如果字符串符合预期的16进制格式则返回true，否则返回false。
     */
    public static boolean isValidHexFormat(String hexData) {
        Matcher matcher = HEX_PATTERN.matcher(hexData);
        return matcher.matches();
    }
    /**
     * 得到数据编码
     * @param bytes 数组字节信息
     * @return
     */
    public static String getEncoding(byte[] bytes){
        UniversalDetector detector = new UniversalDetector(null);
        detector.handleData(bytes, 0, bytes.length);
        detector.dataEnd();
        String encoding = detector.getDetectedCharset();
        if (encoding == null){
            log.info("编码检测失败，开始自定义检测");
            String data = new String(bytes);
            if (isValidHexFormat(data)){
                encoding = HEX_ENCODING;
            }else if (data.getBytes(StandardCharsets.UTF_8).length == bytes.length) {
                encoding = "UTF-8";
            } else if (data.getBytes(StandardCharsets.UTF_16).length == bytes.length) {
                encoding = "UTF-16";
            } else if (data.getBytes(StandardCharsets.ISO_8859_1).length == bytes.length) {
                encoding = "ISO-8859-1";
            }else if (data.getBytes(CharsetUtil.CHARSET_GBK).length == bytes.length) {
                encoding = "GBK";
            }
        }
        detector.reset();
        return encoding;
    }
    /**
     * 得到数据编码
     * @param bytes 数组字节信息
     * @return
     */
    public static JSONMessageData getEncodingData(byte[] bytes){
        String data = new String(bytes);
        MessageFormatDataEnum messageFormatDataEnum = getEncodingMessageFormatDataEnum(data,bytes);
        if (Objects.isNull(messageFormatDataEnum)){
            log.error("数据信息：{}",data);
            return null;
        }
        switch (messageFormatDataEnum){
            case ASCII:
                return FastJsonUtil.toBean(new String(bytes,StandardCharsets.US_ASCII),JSONMessageData.class);
            case HEX:
                return FastJsonUtil.toBean(decodeHexStr(data),JSONMessageData.class);
            case GBK:
                return FastJsonUtil.toBean(new String(bytes,CharsetUtil.CHARSET_GBK),JSONMessageData.class);
            case UTF_8:
                return FastJsonUtil.toBean(new String(bytes,CharsetUtil.CHARSET_UTF_8),JSONMessageData.class);
            case JSON:
                return FastJsonUtil.toBean(data,JSONMessageData.class);
            default:
                return null;
        }

    }
    /**
     * 得到数据编码
     * @param bytes 数组字节信息
     * @return
     */
    public static MessageFormatDataEnum getEncodingMessageFormatDataEnum(String data,byte[] bytes){
        String encoding = null;
        if (isValidHexFormat(data)){
            encoding = HEX_ENCODING;
        }else if (data.getBytes(StandardCharsets.UTF_8).length == bytes.length) {
            encoding = "UTF-8";
        } else if (data.getBytes(StandardCharsets.UTF_16).length == bytes.length) {
            encoding = "UTF-16";
        } else if (data.getBytes(StandardCharsets.ISO_8859_1).length == bytes.length) {
            encoding = "ISO-8859-1";
        }else if (data.getBytes(CharsetUtil.CHARSET_GBK).length == bytes.length) {
            encoding = "GBK";
        } else if (JSONUtil.isTypeJSON(data)) {
            encoding = "JSON";
        }
        if (Objects.isNull(encoding)){
            return null;
        }
        switch (encoding){
            case "UTF-8":
                return MessageFormatDataEnum.UTF_8;
            case "JSON":
                return MessageFormatDataEnum.JSON;
            case "GBK":
                return MessageFormatDataEnum.GBK;
            case HEX_ENCODING:
                return MessageFormatDataEnum.HEX;
            default:
                return null;
        }
    }
    /**
     * 检测文件编码
     * @param filePath 文件路径
     * @return
     * @throws IOException
     */
    public static Charset detectFileEncoding(String filePath) throws IOException {
        FileInputStream fis = new FileInputStream(new File(filePath));
        BufferedInputStream bis = new BufferedInputStream(fis);
        Charset charset = Charset.defaultCharset();
        byte[] buffer = new byte[4096];
        UniversalDetector detector = new UniversalDetector(null);
        int bytesRead;
        while ((bytesRead = bis.read(buffer)) != -1) {
            if (detector.isDone()) {
                break;
            }
            detector.handleData(buffer, 0, bytesRead);
        }
        detector.dataEnd();
        String encoding = detector.getDetectedCharset();
        if (encoding != null) {
            charset = Charset.forName(encoding);
        }
        detector.reset();
        bis.close();
        fis.close();
        return charset;
    }



}
